package com.brillilab.service.logic.experiments;

import com.brillilab.common.alioss.OssFileEnum;
import com.brillilab.common.utils.CodeUtil;
import com.brillilab.domain.enums.common.BoolEnum;
import com.brillilab.domain.enums.experiment.*;
import com.brillilab.domain.enums.inventory.InventoryRecordEnum;
import com.brillilab.domain.enums.kit.KitEnum;
import com.brillilab.domain.enums.experiment.ExperimentStepTextTypeEnum;
import com.brillilab.domain.enums.lab.LabMemberPowerEnum;
import com.brillilab.domain.po.experiments.*;
import com.brillilab.domain.po.experiments.Experiment;
import com.brillilab.domain.po.inventory.ReagentInventory;
import com.brillilab.domain.po.kit.Kit;
import com.brillilab.domain.po.kit.KitSpec;
import com.brillilab.domain.po.kit.Reagent;
import com.brillilab.domain.po.method.*;
import com.brillilab.domain.po.system.FileManage;
import com.brillilab.domain.vo.experiments.*;
import com.brillilab.domain.vo.method.MethodRelateReagentVo;
import com.brillilab.domain.vo.method.MethodStepReagentImportVo;
import com.brillilab.domain.vo.user.UserInfoVo;
import com.brillilab.service.core.experiments.*;
import com.brillilab.service.core.experiments.IExperimentService;
import com.brillilab.service.core.inventory.IInventoryRecordService;
import com.brillilab.service.core.inventory.IReagentInventoryService;
import com.brillilab.service.core.kit.IKitService;
import com.brillilab.service.core.kit.IKitSpecService;
import com.brillilab.service.core.kit.IReagentService;
import com.brillilab.service.core.kit.IReagentTypeService;
import com.brillilab.service.core.lab.ILabMemberPowerService;
import com.brillilab.service.core.lab.ILabMemberService;
import com.brillilab.service.core.method.*;
import com.brillilab.service.core.system.IDictService;
import com.brillilab.service.core.system.IFileManageService;
import com.brillilab.service.quartz.BrillQuartzScheduler;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 实验步骤相关联的 样品/试剂/时间/文本
 *
 * @author WuMenghao
 */
@Service
@Transactional
public class ExperimentStepContentLogic {

    @Resource
    private IDictService dictService;
    @Resource
    private ILabMemberService labMemberService;
    @Resource
    private ILabMemberPowerService labMemberPowerService;
    @Resource
    private IExperimentService experimentService;
    @Resource
    private IExperimentPhaseService experimentPhaseService;
    @Resource
    private IExperimentStepService experimentStepService;
    @Resource
    private IExperimentStepReagentService experimentStepReagentService;
    @Resource
    private ExperimentStepTimerLogic experimentStepTimerLogic;
    @Resource
    private IExperimentStepTimerService experimentStepTimerService;
    @Resource
    private IExperimentStepTextService experimentStepTextService;
    @Resource
    private IExperimentBillService experimentBillService;
    @Resource
    private IPlateGridReagentService plateGridReagentService;
    @Resource
    private IPlateGridTextService plateGridTextService;
    @Resource
    private ExperimentPlateLogic experimentPlateLogic;
    @Resource
    private IExperimentProduceService experimentProduceService;
    @Resource
    private IKitService kitService;
    @Resource
    private IKitSpecService kitSpecService;
    @Resource
    private IReagentService reagentService;
    @Resource
    private IReagentInventoryService reagentInventoryService;
    @Resource
    private IReagentTypeService reagentTypeService;
    @Resource
    private ExperimentLogic experimentLogic;
    @Resource
    private IPlateService plateService;
    @Resource
    private IPlateStepRelateService plateStepRelateService;
    @Resource
    private IPlateGridTimerService plateGridTimerService;
    @Resource
    private IExperimentTroubleShootingService experimentTroubleShootingService;
    @Resource
    private IMethodStepService methodStepService;
    @Resource
    private IMethodPhaseService methodPhaseService;
    @Resource
    private IMethodService methodService;
    @Resource
    private IMethodRelateReagentService methodRelateReagentService;
    @Resource
    private IMethodRelateTimerService methodRelateTimerService;
    @Resource
    private BrillQuartzScheduler scheduler;
    @Resource
    private IFileManageService fileManageService;
    @Resource
    private IInventoryRecordService inventoryRecordService;

    /**
     * 实验步骤中添加Kit时获取Kit对应reagent列表
     *
     * @param kitId
     * @param amount
     * @param labId
     * @param labMemberId
     * @return
     */
    public List<ExperimentStepReagentVo> getKitReagentList(Long kitId,Long groupId,BigDecimal amount,Long labId,Long labMemberId) {

        Kit kit=kitService.selectById(kitId);
        Assert.isTrue(kit != null && kit.getIsDelete().equals(BoolEnum.FALSE.getValue()),"试剂不存在！");

        List<ExperimentStepReagentVo> rs;

        String uuid=CodeUtil.getUUID();
        if(groupId!=null){
            List<ReagentInventory> invList= reagentInventoryService.getInventoryList(kitId,null,groupId);
            Assert.isTrue(invList != null && invList.size() > 0,"库存不存在");
            Assert.isTrue(invList.get(0).getLabId().equals(labId),"试剂不属于该实验室！");

            if(!labMemberService.isOwner(labId,labMemberId)
                    && !labMemberPowerService.isPower(labId,labMemberId,LabMemberPowerEnum.Power.REAGENT)){
                Assert.isTrue(invList.get(0).getLabMemberId() == null
                        || (invList.get(0).getLabMemberId() != null && invList.get(0).getLabMemberId().equals(labMemberId)),"无法使用他人私有试剂！");
            }

            List<Long> reagentIds=invList.stream().map(ReagentInventory::getReagentId).distinct().collect(Collectors.toList());

            //kitSpace
            List<KitSpec> kitSpecs=kitSpecService.selectList(kitId);
            List<KitSpec> last=new ArrayList<>();
            for (Long reagentId : reagentIds) {
                kitSpecs.stream().filter(e -> e.getReagentId().equals(reagentId)).findFirst().ifPresent(last::add);
            }

            //reagentType
            List<Long> reagentTypeIds=invList.stream().map(ReagentInventory::getReagentTypeId).distinct().collect(Collectors.toList());
            Map<Long, Long> reagentTypeMap=reagentTypeService.selectFirstReagentTypeMap(reagentTypeIds);


            rs = last.stream().map(s -> {
                ReagentInventory inventory=invList.stream().filter(e -> e.getReagentId().equals(s.getReagentId())).findFirst().orElse(null);
                if(inventory==null){
                    return null;
                }
                //对应reagent的量
                BigDecimal thisSize=amount.multiply(BigDecimal.valueOf(s.getMultiple()).multiply(s.getSize())).divide(s.getKitSize(),3,RoundingMode.HALF_UP);
                ExperimentStepReagentVo stepReagentVo=new ExperimentStepReagentVo();
                stepReagentVo.setName(inventory.getReagentName());
                stepReagentVo.setReagentId(s.getReagentId());
                stepReagentVo.setAmount(thisSize);
                stepReagentVo.setUuid(uuid);
                stepReagentVo.setClassify(inventory.getClassify());
                stepReagentVo.setKitId(s.getKitId());
                stepReagentVo.setType(ExperimentStepReagentTypeEnum.KIT.getValue());
                stepReagentVo.setGroupId(groupId);
                stepReagentVo.setFirstReagentTypeId(reagentTypeMap.get(inventory.getReagentTypeId()));
                return stepReagentVo;
            }).filter(Objects::nonNull).collect(Collectors.toList());
        } else {
            List<Reagent> reagents=reagentService.selectList(kitId);

            //reagentType
            List<Long> reagentTypeIds=reagents.stream().map(Reagent::getReagentTypeId).distinct().collect(Collectors.toList());
            Map<Long, Long> reagentTypeMap=reagentTypeService.selectFirstReagentTypeMap(reagentTypeIds);


            rs = reagents.stream().filter(e -> e.getIsDelete().equals(BoolEnum.FALSE.getValue())).map(r -> {

                ExperimentStepReagentVo stepReagentVo=new ExperimentStepReagentVo();
                stepReagentVo.setName(r.getName());
                stepReagentVo.setReagentId(r.getId());
                stepReagentVo.setAmount(BigDecimal.ZERO);
                stepReagentVo.setUuid(uuid);
                stepReagentVo.setKitId(r.getKitId());
                stepReagentVo.setClassify(r.getClassify());
                stepReagentVo.setType(ExperimentStepReagentTypeEnum.KIT.getValue());
                stepReagentVo.setFirstReagentTypeId(reagentTypeMap.get(r.getReagentTypeId()));
                return stepReagentVo;
            }).collect(Collectors.toList());
        }
        return rs;
    }

    /**
     * 实验步骤中添加试剂/样品成分
     *
     * @param experimentId
     * @param phaseId
     * @param stepId
     * @param content
     * @param items
     * @param userInfo
     */
    public void addReagentToStep(Long experimentId,Long phaseId,Long stepId,String content,List<ExperimentStepReagentVo> items,UserInfoVo userInfo) {

        Long labId = userInfo.getLabId();
        Long labMemberId = userInfo.getLabMemberId();
        Experiment experiment=experimentService.selectById(experimentId);
        Assert.notNull(experiment,"实验不存在！");
        Assert.isTrue(experiment.getLabId().equals(labId),"实验不属于该实验室！");
        Assert.isTrue(experiment.getExecutorId().equals(labMemberId),"您不是该实验的执行人，无法进行此操作！");

        ExperimentPhase phase=experimentPhaseService.selectById(phaseId);
        Assert.notNull(phase,"实验阶段不存在！");
        Assert.isTrue(phase.getExperimentId().equals(experimentId) ,"该阶段不属于本实验！");

        ExperimentStep step=experimentStepService.selectById(stepId);
        Assert.notNull(step,"实验步骤不存在！");
        Assert.isTrue(step.getExperimentId().equals(experimentId) ,"该步骤不属于本实验！");
        Assert.isTrue(step.getExperimentPhaseId().equals(phaseId) ,"该步骤不属于本阶段！");

        //步骤开始
        experimentStepService.startStep(stepId);

        List<ExperimentStepReagent> stepReagents=experimentStepReagentService.selectExperimentStepReagentList(experimentId,phaseId,stepId);

        //插入关联试剂记录
        Map<Integer, String> unitMap=dictService.getUnitMap();
        List<Long> reagentIds=items.stream().map(ExperimentStepReagentVo::getReagentId).collect(Collectors.toList());
        //reagents
        List<Reagent> reagents=reagentService.selectByReagentIds(reagentIds);
        Assert.notNull(reagents,"相关试剂成分不存在！");

        //inventories
//        List<Long> sampleIds=reagents.stream().filter(e -> e.getClassify().equals(KitEnum.Classify.SAMPLE.getValue())).map(Reagent::getId).collect(Collectors.toList());
        List<ReagentInventory> sampleInventories=reagentInventoryService.selectByReagentIdList(reagentIds,null);

        //kits
        List<Long> kitIds=reagents.stream().map(Reagent::getKitId).distinct().collect(Collectors.toList());
        List<Kit> kits=kitService.selectByIds(kitIds);
        Assert.notNull(kits,"相关试剂不存在！");
        //firstReagentTypeMap
        List<Long> reagentTypeIds=reagents.stream().map(Reagent::getReagentTypeId).collect(Collectors.toList());
        Map<Long, Long> firstReagentTypeMap=reagentTypeService.selectFirstReagentTypeMap(reagentTypeIds);
        //experimentStepReagents
        List<ExperimentStepReagent> experimentStepReagents=items.stream().map(e -> {

            /* 允许重复，type为kit，关联Kit新需求 */
            if(ExperimentStepReagentTypeEnum.REAGENT.getValue().equals(e.getType())){
                e.setUuid(e.getUuid().trim());
                ExperimentStepReagent exist=stepReagents.stream().filter(r -> r.getUuid().equals(e.getUuid())).findFirst().orElse(null);
                Assert.isNull(exist,"uuid 重复，请检查参数！");
            }

            Reagent reagent=reagents.stream().filter(r -> e.getReagentId().equals(r.getId())).findFirst().orElse(null);
            Assert.isTrue(reagent != null && reagent.getIsDelete().equals(BoolEnum.FALSE.getValue()),"试剂成分不存在！");

            Kit kit=kits.stream().filter(k -> k.getId().equals(reagent.getKitId())).findFirst().orElse(null);
            Assert.isTrue(kit!=null && kit.getIsDelete().equals(BoolEnum.FALSE.getValue()),"相关试剂不存在！");

            ExperimentStepReagent experimentStepReagent=new ExperimentStepReagent();
            experimentStepReagent.setExperimentId(experimentId);
            experimentStepReagent.setPhaseId(phaseId);
            experimentStepReagent.setStepId(stepId);
            experimentStepReagent.setReagentId(reagent.getId());
            experimentStepReagent.setClassify(reagent.getClassify());
            experimentStepReagent.setName(reagent.getName());
            experimentStepReagent.setKitName(kit.getName());
            experimentStepReagent.setKitId(kit.getId());
            String alias=getReagentAlias(reagent,kit);
            experimentStepReagent.setAlias(alias);
            if(reagent.getClassify().equals(KitEnum.Classify.SAMPLE.getValue())){
                ReagentInventory inventory=sampleInventories.stream().filter(r -> r.getReagentId().equals(reagent.getId())).findFirst().orElse(null);
                experimentStepReagent.setAmount(inventory!=null ? inventory.getAmount() : BigDecimal.ZERO);
            }else {
                experimentStepReagent.setAmount(e.getAmount());
            }
            experimentStepReagent.setUuid(e.getUuid());
            experimentStepReagent.setUnit(unitMap.get(reagent.getUnit()));
            experimentStepReagent.setFirstReagentTypeId(firstReagentTypeMap.get(reagent.getReagentTypeId()));
            experimentStepReagent.setGroupId(e.getGroupId());
            if(e.getType() == null || (e.getType()!=null && (e.getType()<=0  || e.getType()>2))){
                experimentStepReagent.setType(ExperimentStepReagentTypeEnum.REAGENT.getValue());
            }else {
                experimentStepReagent.setType(e.getType());
            }

            return experimentStepReagent;
        }).collect(Collectors.toList());

        if(experimentStepReagents.size()>0){
            experimentStepReagentService.insertBatch(experimentStepReagents);
        }

        List<ExperimentStepReagent> allStepReagents = experimentStepReagentService.selectExperimentStepReagentList(experimentId,phaseId,stepId);
        List<ExperimentBill> bills=items.stream().map(e -> {
            e.setUuid(e.getUuid().trim());
            Reagent reagent=reagents.stream().filter(r -> e.getReagentId().equals(r.getId())).findFirst().orElse(null);
            Assert.isTrue(reagent != null && reagent.getIsDelete().equals(BoolEnum.FALSE.getValue()),"试剂成分不存在！");
            ExperimentStepReagent experimentStepReagent=allStepReagents.stream().filter(esr ->e.getReagentId().equals(esr.getReagentId()) && e.getUuid().equals(esr.getUuid())).findFirst().orElse(null);
            ExperimentBill experimentBill=new ExperimentBill();
            experimentBill.setExperimentId(experimentId);
            experimentBill.setPhaseId(phaseId);
            experimentBill.setPhaseSort(phase.getSort());
            experimentBill.setStepId(stepId);
            experimentBill.setStepSort(step.getSort());
            experimentBill.setSource(ExperimentBillSourceEnum.REAGENT.getSource());
            experimentBill.setSourceId(experimentStepReagent.getReagentId());
            experimentBill.setStepReagentId(experimentStepReagent.getId());
            experimentBill.setClassify(experimentStepReagent.getClassify());
            experimentBill.setName(experimentStepReagent.getName());
            experimentBill.setAlias(experimentStepReagent.getAlias());
            experimentBill.setAmount(experimentStepReagent.getAmount()!=null?experimentStepReagent.getAmount():BigDecimal.ZERO);
            experimentBill.setUnit(reagent.getUnit());
            experimentBill.setFirstReagentTypeId(firstReagentTypeMap.get(reagent.getReagentTypeId()));
            experimentBill.setType(experimentStepReagent.getType());
            experimentBill.setKitId(experimentStepReagent.getKitId());
            experimentBill.setKitName(experimentStepReagent.getKitName());

            return experimentBill;
        }).collect(Collectors.toList());

        if(bills.size()>0){
            experimentBillService.insertBatch(bills);
        }

        //更新步骤内容
        step.setContent(content);
        experimentStepService.updateById(step);
        experimentService.updateByNewMethod(step.getExperimentId());
    }

    public String getReagentAlias(Reagent reagent,Kit kit) {
        String alias = null;
        if(kit.getKitType().equals(KitEnum.KitType.ONE.getValue())){
            if(!StringUtils.isEmpty(reagent.getAlias())){
                alias = reagent.getAlias();
                alias = alias.split(",")[0];
            }else {
                alias = kit.getAlias();
                if(!StringUtils.isEmpty(kit.getAlias())){
                    alias = alias.split(",")[0];
                }else {
                    alias = kit.getName().substring(0,kit.getName().length()<=6 ? kit.getName().length():6);
                }
            }
        }else {
            alias = reagent.getAlias();
            if(!StringUtils.isEmpty(reagent.getAlias())){
                alias = alias.split(",")[0];
            }else {
                alias = reagent.getName().substring(0,reagent.getName().length()<=6 ? reagent.getName().length():6);
            }
        }
        return alias;
    }

    /**
     * 实验步骤中添加试剂/样品成分
     *
     * @param experimentId
     * @param phaseId
     * @param stepId
     * @param content
     * @param items
     * @param labId
     * @param labMemberId
     */
    public void addReagentToStepNew(Long experimentId,Long phaseId,Long stepId,String content,List<ExperimentStepReagentVo> items,Long labId,Long labMemberId) {

        Experiment experiment=experimentService.selectById(experimentId);
        Assert.notNull(experiment,"实验不存在！");
        Assert.isTrue(experiment.getLabId().equals(labId),"实验不属于该实验室！");
        Assert.isTrue(experiment.getExecutorId().equals(labMemberId),"您不是该实验的执行人，无法进行此操作！");

        ExperimentPhase phase=experimentPhaseService.selectById(phaseId);
        Assert.notNull(phase,"实验阶段不存在！");
        Assert.isTrue(phase.getExperimentId().equals(experimentId) ,"该阶段不属于本实验！");

        ExperimentStep step=experimentStepService.selectById(stepId);
        Assert.notNull(step,"实验步骤不存在！");
        Assert.isTrue(step.getExperimentId().equals(experimentId) ,"该步骤不属于本实验！");
        Assert.isTrue(step.getExperimentPhaseId().equals(phaseId) ,"该步骤不属于本阶段！");


        List<ExperimentStepReagent> stepReagents=experimentStepReagentService.selectExperimentStepReagentList(experimentId,phaseId,stepId);


        //插入关联试剂记录
        Map<Integer, String> unitMap=dictService.getUnitMap();
        List<Long> reagentIds=items.stream().map(ExperimentStepReagentVo::getReagentId).collect(Collectors.toList());
        List<Long> itemKitIds=items.stream().map(ExperimentStepReagentVo::getKitId).collect(Collectors.toList());
        List<Long> itemGroupIds=items.stream().map(ExperimentStepReagentVo::getGroupId).collect(Collectors.toList());

        //kitspec
        List<KitSpec> kitSpecs=kitSpecService.selectList(itemKitIds);

        //inventories
//        List<Long> sampleIds=reagents.stream().filter(e -> e.getClassify().equals(KitEnum.Classify.SAMPLE.getValue())).map(Reagent::getId).collect(Collectors.toList());
        List<ReagentInventory> inventories=reagentInventoryService.selectByReagentIdList(reagentIds,null);
        List<ReagentInventory> inventoriesKit=reagentInventoryService.selectListByKitIdList(itemKitIds,itemGroupIds);
        inventories.addAll(inventoriesKit);

        //reagents
        reagentIds=inventories.stream().map(ReagentInventory::getReagentId).distinct().collect(Collectors.toList());
        List<Reagent> kitReagents=reagentService.selectByIds(itemKitIds);
        List<Reagent> reagents=reagentService.selectByReagentIds(reagentIds);
        reagents.addAll(kitReagents);
        Assert.notNull(reagents,"相关试剂成分不存在！");

        //kits
        List<Long> kitIds=items.stream().map(ExperimentStepReagentVo::getKitId).distinct().collect(Collectors.toList());
        List<Kit> kits=kitService.selectByIds(kitIds);
        Assert.notNull(kits,"相关试剂不存在！");

        //firstReagentTypeMap
        List<Long> reagentTypeIds=reagents.stream().map(Reagent::getReagentTypeId).collect(Collectors.toList());
        Map<Long, Long> firstReagentTypeMap=reagentTypeService.selectFirstReagentTypeMap(reagentTypeIds);

        //experimentStepReagents
        List<ExperimentStepReagent> experimentStepReagents=new ArrayList<>();
        items.forEach(e -> {

            /* 允许重复，type为kit，关联Kit新需求 */
            if(ExperimentStepReagentTypeEnum.REAGENT.getValue().equals(e.getType())){
                e.setUuid(e.getUuid().trim());
                ExperimentStepReagent exist=stepReagents.stream().filter(r -> r.getUuid().equals(e.getUuid())).findFirst().orElse(null);
                Assert.isNull(exist,"uuid 重复，请检查参数！");
            }

            if(e.getKitId()!=null && e.getGroupId()!=null){
                List<ReagentInventory> kitInventories=inventories.stream().filter(inventory -> inventory.getKitId().equals(e.getKitId()) && inventory.getGroupId().equals(e.getGroupId())).collect(Collectors.toList());
                Kit kit=kits.stream().filter(k -> k.getId().equals(e.getKitId())).findFirst().orElse(null);
                if(kit!=null){
                    List<ExperimentStepReagent> thisStepReagent=kitInventories.stream().map(inventory -> {
                        Reagent reagent=reagents.stream().filter(r -> r.getId().equals(inventory.getReagentId())).findFirst().orElse(null);
                        if(reagent!=null){
                            KitSpec kitSpec=kitSpecs.stream().filter(ks -> ks.getReagentId().equals(reagent.getId())).findFirst().orElse(null);
                            BigDecimal thisSize=kitSpec!=null ? e.getAmount().multiply(BigDecimal.valueOf(kitSpec.getMultiple()).multiply(kitSpec.getSize())).divide(kitSpec.getKitSize(),3,RoundingMode.HALF_UP) : BigDecimal.ZERO;
                            ExperimentStepReagent experimentStepReagent=new ExperimentStepReagent();
                            experimentStepReagent.setExperimentId(experimentId);
                            experimentStepReagent.setPhaseId(phaseId);
                            experimentStepReagent.setStepId(stepId);
                            experimentStepReagent.setReagentId(reagent.getId());
                            experimentStepReagent.setClassify(reagent.getClassify());
                            experimentStepReagent.setName(reagent.getName());
                            experimentStepReagent.setKitName(kit.getName());
                            experimentStepReagent.setKitId(kit.getId());
                            String alias=getReagentAlias(reagent,kit);
                            experimentStepReagent.setAlias(alias);
                            if(reagent.getClassify().equals(KitEnum.Classify.SAMPLE.getValue())){
                                experimentStepReagent.setAmount(inventory.getAmount());
                            } else {
                                experimentStepReagent.setAmount(thisSize);
                            }
                            experimentStepReagent.setUuid(e.getUuid());
                            experimentStepReagent.setUnit(unitMap.get(reagent.getUnit()));
                            experimentStepReagent.setFirstReagentTypeId(firstReagentTypeMap.get(reagent.getReagentTypeId()));
                            experimentStepReagent.setGroupId(e.getGroupId());
                            if(e.getType() == null || (e.getType() != null && (e.getType() <= 0 || e.getType() > 2))){
                                experimentStepReagent.setType(ExperimentStepReagentTypeEnum.REAGENT.getValue());
                            } else {
                                experimentStepReagent.setType(e.getType());
                            }
                            return experimentStepReagent;
                        }
                        return null;
                    }).filter(Objects::nonNull).collect(Collectors.toList());
                    experimentStepReagents.addAll(thisStepReagent);
                }
            }else if(e.getKitId()!=null && e.getGroupId()==null){

                List<Reagent> thisReagents=reagents.stream().filter(r -> r.getKitId().equals(e.getKitId())).collect(Collectors.toList());
                thisReagents.forEach(reagent -> {
                    Kit kit=kits.stream().filter(k -> k.getId().equals(e.getKitId())).findFirst().orElse(null);
                    if(kit!=null){
                        ExperimentStepReagent experimentStepReagent=new ExperimentStepReagent();
                        experimentStepReagent.setExperimentId(experimentId);
                        experimentStepReagent.setPhaseId(phaseId);
                        experimentStepReagent.setStepId(stepId);
                        experimentStepReagent.setReagentId(reagent.getId());
                        experimentStepReagent.setClassify(reagent.getClassify());
                        experimentStepReagent.setName(reagent.getName());
                        experimentStepReagent.setKitName(kit.getName());
                        experimentStepReagent.setKitId(kit.getId());
                        String alias=getReagentAlias(reagent,kit);
                        experimentStepReagent.setAlias(alias);
                        experimentStepReagent.setAmount(e.getAmount());
                        experimentStepReagent.setUuid(e.getUuid());
                        experimentStepReagent.setUnit(unitMap.get(reagent.getUnit()));
                        experimentStepReagent.setFirstReagentTypeId(firstReagentTypeMap.get(reagent.getReagentTypeId()));
                        experimentStepReagent.setGroupId(e.getGroupId());
                        if(e.getType() == null || (e.getType()!=null && (e.getType()<=0  || e.getType()>2))){
                            experimentStepReagent.setType(ExperimentStepReagentTypeEnum.REAGENT.getValue());
                        }else {
                            experimentStepReagent.setType(e.getType());
                        }

                        experimentStepReagents.add(experimentStepReagent);
                    }
                });
            } else if(e.getReagentId()!=null){

                Reagent reagent=reagents.stream().filter(r -> e.getReagentId().equals(r.getId())).findFirst().orElse(null);
                Assert.isTrue(reagent != null && reagent.getIsDelete().equals(BoolEnum.FALSE.getValue()),"试剂成分不存在！");

                Kit kit=kits.stream().filter(k -> k.getId().equals(reagent.getKitId())).findFirst().orElse(null);
                Assert.isTrue(kit!=null && kit.getIsDelete().equals(BoolEnum.FALSE.getValue()),"相关试剂不存在！");

                ExperimentStepReagent experimentStepReagent=new ExperimentStepReagent();
                experimentStepReagent.setExperimentId(experimentId);
                experimentStepReagent.setPhaseId(phaseId);
                experimentStepReagent.setStepId(stepId);
                experimentStepReagent.setReagentId(reagent.getId());
                experimentStepReagent.setClassify(reagent.getClassify());
                experimentStepReagent.setName(reagent.getName());
                experimentStepReagent.setKitName(kit.getName());
                experimentStepReagent.setKitId(kit.getId());
                String alias=getReagentAlias(reagent,kit);
                experimentStepReagent.setAlias(alias);
                if(reagent.getClassify().equals(KitEnum.Classify.SAMPLE.getValue())){
                    ReagentInventory inventory=inventories.stream().filter(r -> r.getReagentId().equals(reagent.getId())).findFirst().orElse(null);
                    experimentStepReagent.setAmount(inventory!=null ? inventory.getAmount() : BigDecimal.ZERO);
                }else {
                    experimentStepReagent.setAmount(e.getAmount());
                }
                experimentStepReagent.setUuid(e.getUuid());
                experimentStepReagent.setUnit(unitMap.get(reagent.getUnit()));
                experimentStepReagent.setFirstReagentTypeId(firstReagentTypeMap.get(reagent.getReagentTypeId()));
                experimentStepReagent.setGroupId(e.getGroupId());
                if(e.getType() == null || (e.getType()!=null && (e.getType()<=0  || e.getType()>2))){
                    experimentStepReagent.setType(ExperimentStepReagentTypeEnum.REAGENT.getValue());
                }else {
                    experimentStepReagent.setType(e.getType());
                }

                experimentStepReagents.add(experimentStepReagent);
            }
        });

        if(experimentStepReagents.size()>0){
            experimentStepReagentService.insertBatch(experimentStepReagents);
        }

        List<ExperimentStepReagent> allStepReagents = experimentStepReagentService.selectExperimentStepReagentList(experimentId,phaseId,stepId);
        List<ExperimentBill> bills=experimentStepReagents.stream().map(e -> {
            e.setUuid(e.getUuid().trim());
            Reagent reagent=reagents.stream().filter(r -> e.getReagentId().equals(r.getId())).findFirst().orElse(null);
            Assert.isTrue(reagent != null && reagent.getIsDelete().equals(BoolEnum.FALSE.getValue()),"试剂成分不存在！");
            ExperimentStepReagent experimentStepReagent=allStepReagents.stream().filter(esr -> e.getUuid().equals(esr.getUuid())).findFirst().orElse(null);
            ExperimentBill experimentBill=new ExperimentBill();
            experimentBill.setExperimentId(experimentId);
            experimentBill.setPhaseId(phaseId);
            experimentBill.setPhaseSort(phase.getSort());
            experimentBill.setStepId(stepId);
            experimentBill.setStepSort(step.getSort());
            experimentBill.setSource(ExperimentBillSourceEnum.REAGENT.getSource());
            experimentBill.setSourceId(experimentStepReagent.getReagentId());
            experimentBill.setStepReagentId(experimentStepReagent.getId());
            experimentBill.setClassify(experimentStepReagent.getClassify());
            experimentBill.setName(experimentStepReagent.getName());
            experimentBill.setAlias(experimentStepReagent.getAlias());
            experimentBill.setAmount(experimentStepReagent.getAmount()!=null?experimentStepReagent.getAmount():BigDecimal.ZERO);
            experimentBill.setUnit(reagent.getUnit());
            experimentBill.setFirstReagentTypeId(firstReagentTypeMap.get(reagent.getReagentTypeId()));
            
            experimentBill.setType(experimentStepReagent.getType());
            experimentBill.setKitId(experimentStepReagent.getKitId());
            experimentBill.setKitName(experimentStepReagent.getKitName());
            return experimentBill;
        }).collect(Collectors.toList());

        if(bills.size()>0){
            experimentBillService.insertBatch(bills);
        }

        //更新步骤内容
        step.setContent(content);
        experimentStepService.updateById(step);
        experimentService.updateByNewMethod(step.getExperimentId());
    }

    /**
     * 实验步骤中添加文本
     *
     * @param experimentId
     * @param phaseId
     * @param stepId
     * @param content
     * @param labId
     * @param labMemberId
     */
    public ExperimentStepTextVo addTextToStep(Long experimentId,Long phaseId,Long stepId,String content,Long labId,Long labMemberId) {
        //校验
        experimentStepService.getExperimentStepAndAssertExist(experimentId,phaseId,stepId,labId,labMemberId);

        //新建插入
        ExperimentStepText experimentStepText=new ExperimentStepText();
        experimentStepText.setExperimentId(experimentId);
        experimentStepText.setPhaseId(phaseId!=null ? phaseId : 0);
        experimentStepText.setStepId(stepId!=null ? stepId : 0);
        experimentStepText.setContent(content);
        experimentStepText.setType(ExperimentStepTextTypeEnum.NORMAL.getValue());
        experimentStepTextService.insert(experimentStepText);

        ExperimentStepTextVo textVo=new ExperimentStepTextVo();
        textVo.setContent(experimentStepText.getContent());
        textVo.setId(experimentStepText.getId());

        return textVo;
    }

    /**
     * 实验步骤中计时器添加
     *
     * @param experimentId
     * @param phaseId
     * @param time
     * @param labId
     * @param labMemberId
     * @return
     */
    public ExperimentStepTimerVo addTimerToStep(Long experimentId,Long phaseId,Long stepId,Long time,List<Long> timeList,Long labId,Long labMemberId) {

        Experiment experiment=experimentService.selectById(experimentId);
        Assert.notNull(experiment,"实验不存在!");
        List<ExperimentPhase> experimentPhases=experimentPhaseService.selectList(experimentId);
        Assert.isTrue(experiment.getMethodId()!=null || !CollectionUtils.isEmpty(experimentPhases),"实验暂无步骤，无法添加计时器，请先关联方法或添加步骤再进行此操作!");

        //校验
        experimentStepService.getExperimentStepAndAssertExist(experimentId,phaseId,stepId,labId,labMemberId);

        List<ExperimentStepTimer> experimentStepTimers = experimentStepTimerService.selectList(experimentId, phaseId, stepId);
        int timerCount = experimentStepTimers != null ? experimentStepTimers.size() : 0;

        //添加计时器逻辑
        if(timeList == null) {
            timeList = new ArrayList<>();
        }
        if(time!=null && CollectionUtils.isEmpty(timeList)) {
            timeList.add(time);
        }
        Assert.isTrue(timerCount+timeList.size() <= 8, "新增计时器个数超限，每个步骤最多只支持8个计时器！");
        return experimentStepTimerLogic.addTimerToStepBatch(experimentId,phaseId,stepId,timeList);
    }


    /**
     * 实验步骤列表文本
     *
     * @param experimentId
     * @param phaseId
     * @param stepId
     * @param labId
     * @return
     */
    @SuppressWarnings("ResultOfMethodCallIgnored")
    public List<ExperimentStepTextGroupVo> getStepTextList(Long experimentId,Long phaseId,Long stepId,Long labId) {

        //校验
        getExperimentStepAndAssertExist(experimentId,phaseId,stepId,labId,null);

        List<ExperimentStepText> texts=experimentStepTextService.selectList(experimentId,phaseId,stepId);
        List<ExperimentStepText> sample=texts.stream().filter(e -> TextGroupTypeEnum.SAMPLE.getValue().equals(e.getGroupType())).collect(Collectors.toList());
        List<ExperimentStepText> control=texts.stream().filter(e -> TextGroupTypeEnum.CONTROL.getValue().equals(e.getGroupType())).collect(Collectors.toList());
        List<ExperimentStepText> test=texts.stream().filter(e -> TextGroupTypeEnum.TEST.getValue().equals(e.getGroupType())).collect(Collectors.toList());
        List<ExperimentStepText> other=texts.stream().filter(e -> TextGroupTypeEnum.OTHER.getValue().equals(e.getGroupType())).collect(Collectors.toList());

        List<ExperimentStepTextGroupVo> groupVos=new ArrayList<>();
        if(!CollectionUtils.isEmpty(sample)){
            ExperimentStepTextGroupVo experimentStepTextGroupVo=new ExperimentStepTextGroupVo();
            List<ExperimentStepTextVo> sampleVo=sample.stream().map(this::getExperimentStepTextVo).collect(Collectors.toList());
            experimentStepTextGroupVo.setName(TextGroupTypeEnum.SAMPLE.getName());
            experimentStepTextGroupVo.setType(TextGroupTypeEnum.SAMPLE.getValue());
            experimentStepTextGroupVo.setTextList(sampleVo);
            groupVos.add(experimentStepTextGroupVo);
        }
        if(!CollectionUtils.isEmpty(control)){
            ExperimentStepTextGroupVo experimentStepTextGroupVo=new ExperimentStepTextGroupVo();
            List<ExperimentStepTextVo> sampleVo=control.stream().map(this::getExperimentStepTextVo).collect(Collectors.toList());
            experimentStepTextGroupVo.setName(TextGroupTypeEnum.CONTROL.getName());
            experimentStepTextGroupVo.setType(TextGroupTypeEnum.CONTROL.getValue());
            experimentStepTextGroupVo.setTextList(sampleVo);
            groupVos.add(experimentStepTextGroupVo);
        }
        if(!CollectionUtils.isEmpty(test)){
            ExperimentStepTextGroupVo experimentStepTextGroupVo=new ExperimentStepTextGroupVo();
            List<ExperimentStepTextVo> sampleVo=test.stream().map(this::getExperimentStepTextVo).collect(Collectors.toList());
            experimentStepTextGroupVo.setName(TextGroupTypeEnum.TEST.getName());
            experimentStepTextGroupVo.setType(TextGroupTypeEnum.TEST.getValue());
            experimentStepTextGroupVo.setTextList(sampleVo);
            groupVos.add(experimentStepTextGroupVo);
        }
        if(!CollectionUtils.isEmpty(other)){
            ExperimentStepTextGroupVo experimentStepTextGroupVo=new ExperimentStepTextGroupVo();
            List<ExperimentStepTextVo> sampleVo=other.stream().map(this::getExperimentStepTextVo).collect(Collectors.toList());
            experimentStepTextGroupVo.setName(TextGroupTypeEnum.OTHER.getName());
            experimentStepTextGroupVo.setType(TextGroupTypeEnum.OTHER.getValue());
            experimentStepTextGroupVo.setTextList(sampleVo);
            groupVos.add(experimentStepTextGroupVo);
        }

        return groupVos;
    }

    private ExperimentStepTextVo getExperimentStepTextVo(ExperimentStepText t) {
        ExperimentStepTextVo textVo=new ExperimentStepTextVo();
        textVo.setId(t.getId());
        textVo.setContent(t.getContent());
        return textVo;
    }

    /**
     * 实验步骤列表试剂
     *
     * @param experimentId
     * @param phaseId
     * @param stepId
     * @param labId
     * @return
     */
    public List<ExperimentStepMaterialVo> getStepKitReagentList(Long experimentId,Long phaseId,Long stepId,Long labId) {

        //校验
        getExperimentStepAndAssertExist(experimentId,phaseId,stepId,labId,null);

        Map<Integer, String> unitMap=dictService.getUnitMap();

        if(phaseId==null || stepId==null){
            return Collections.emptyList();
        }

        //实验中的样品
        List<ExperimentBill> stepBills=experimentBillService.selectList(experimentId,phaseId,stepId);
        List<ExperimentStepMaterialVo> stepReagent=stepBills.stream().filter(e ->e.getClassify().equals(KitEnum.Classify.REAGENT.getValue())).map(rb -> {
            return getExperimentStepMaterialVo(unitMap,rb,stepId);
        }).collect(Collectors.toList());

        return stepReagent;
    }

    /**
     * 实验步骤列表试剂全部
     *
     * @param experimentId
     * @param labId
     * @return
     */
    public List<ExperimentStepMaterialVo> getExperimentReagentList(Long experimentId,Long phaseId,Long stepId,Long labId) {

        Experiment experiment=experimentService.selectById(experimentId);
        Assert.notNull(experiment,"实验不存在！");
        Assert.isTrue(experiment.getLabId().equals(labId),"实验不属于该实验室！");

        Map<Integer, String> unitMap=dictService.getUnitMap();

        //实验中的样品
        List<ExperimentBill> bills=experimentBillService.selectList(experimentId);
        if(phaseId!=null && stepId!=null){

            List<ExperimentStepMaterialVo> reagent=bills.stream().filter(e ->e.getClassify().equals(KitEnum.Classify.REAGENT.getValue()) && !stepId.equals(e.getStepId())).map(rb -> {
                return getExperimentStepMaterialVo(unitMap,rb,stepId);
            }).collect(Collectors.toList());
            return reagent;
        }else {
            List<ExperimentStepMaterialVo> reagent=bills.stream().filter(e ->e.getClassify().equals(KitEnum.Classify.REAGENT.getValue())).map(rb -> {
                return getExperimentStepMaterialVo(unitMap,rb,stepId);
            }).collect(Collectors.toList());
            return reagent;
        }
    }

    /**
     * 实验步骤列表样品
     *
     * @param experimentId
     * @param phaseId
     * @param stepId
     * @param labId
     * @return
     */
    public List<ExperimentStepMaterialVo> getStepSampleReagentList(Long experimentId,Long phaseId,Long stepId,Long labId) {

        Map<Integer, String> unitMap=dictService.getUnitMap();

        //校验
        getExperimentStepAndAssertExist(experimentId,phaseId,stepId,labId,null);

        //实验中的样品
        List<ExperimentBill> stepBills=experimentBillService.selectList(experimentId,phaseId,stepId);
        List<ExperimentStepMaterialVo> stepSample=stepBills.stream().filter(e ->e.getClassify().equals(KitEnum.Classify.SAMPLE.getValue())).map(rb -> {
            return getExperimentStepMaterialVo(unitMap,rb,stepId);
        }).collect(Collectors.toList());

        return stepSample;
    }

    /**
     * 实验步骤列表样品全部样品
     *
     * @param experimentId
     * @param labId
     * @return
     */
    public List<ExperimentStepMaterialVo> getExperimentSampleList(Long experimentId,Long labId,Long stepId) {

        Experiment experiment=experimentService.selectById(experimentId);
        Assert.notNull(experiment,"实验不存在！");
        Assert.isTrue(experiment.getLabId().equals(labId),"实验不属于该实验室！");

        Map<Integer, String> unitMap=dictService.getUnitMap();

        //实验中的样品
        List<ExperimentBill> bills=experimentBillService.selectList(experimentId);

        List<ExperimentStepMaterialVo> expSample=bills.stream().filter(e ->e.getClassify().equals(KitEnum.Classify.SAMPLE.getValue())).map(rb -> {
            return getExperimentStepMaterialVo(unitMap,rb,stepId);
        }).collect(Collectors.toList());
        return expSample;

    }

    private ExperimentStepMaterialVo getExperimentStepMaterialVo(Map<Integer, String> unitMap,ExperimentBill rb,Long stepId) {
        ExperimentStepMaterialVo materialVo=new ExperimentStepMaterialVo();
        materialVo.setId(rb.getId());
        materialVo.setReagentId(rb.getSourceId());
        materialVo.setFirstReagentTypeId(rb.getFirstReagentTypeId());
        materialVo.setName(rb.getName());
        materialVo.setAlias(rb.getAlias());
        materialVo.setAmount(rb.getAmount());
        materialVo.setUnit(unitMap.get(rb.getUnit()));
        materialVo.setClassify(rb.getClassify());
        materialVo.setType(ExperimentStepMaterialTypeEnum.EXPERIMENT_SAMPLE.getType());
        materialVo.setIsCurrentStep(stepId != null && stepId.equals(rb.getStepId()));
        return materialVo;
    }

    /**
     * 实验步骤列表计时器
     *
     * @param experimentId
     * @param phaseId
     * @param stepId
     * @param labId
     * @return
     */
    public List<ExperimentStepTimerVo> getStepTimerList(Long experimentId,Long phaseId,Long stepId,Long labId) {

        //校验
        getExperimentStepAndAssertExist(experimentId,phaseId,stepId,labId,null);

        List<ExperimentStepTimer> timers=experimentStepTimerService.selectList(experimentId,phaseId,stepId);

        return timers.stream().map(t -> {
            ExperimentStepTimerVo timerVo=new ExperimentStepTimerVo();
            BeanUtils.copyProperties(t,timerVo);
            if(t.getState().equals(ExperimentStepTimerStateEnum.START.getState())){
                Date nextFireTime=scheduler.getNextFireTime(t.getJobName(),t.getJobGroup());
                long remain=0;
                if(nextFireTime!=null){
                    remain = nextFireTime.getTime() - System.currentTimeMillis();
                }
                timerVo.setRemainTime(remain >= 1000L ? remain : 0);
                timerVo.setState(remain >= 1000L ? t.getState() : ExperimentStepTimerStateEnum.END.getState());
            }
            return timerVo;
        }).collect(Collectors.toList());
    }

    /**
     * 实验步骤详情
     *
     * @param experimentId
     * @param phaseId
     * @param stepId
     * @param labId
     * @return
     */
    public ExperimentStepDetailVo getStepDetail(Long experimentId,Long phaseId,Long stepId,Long labId) {

        //实验
        Experiment experiment=experimentService.selectById(experimentId);
        Assert.notNull(experiment,"实验不存在！");
        Assert.isTrue(experiment.getLabId().equals(labId),"实验不属于该实验室！");

        //阶段
        ExperimentPhase phase=experimentPhaseService.selectById(phaseId);
        Assert.notNull(phase,"实验阶段不存在！");
        Assert.isTrue(phase.getExperimentId().equals(experimentId),"该阶段不属于本实验！");

        //步骤
        ExperimentStep step=experimentStepService.selectById(stepId);
        Assert.notNull(step,"实验步骤不存在！");
        Assert.isTrue(step.getExperimentId().equals(experimentId),"该步骤不属于本实验！");
        Assert.isTrue(step.getExperimentPhaseId().equals(phaseId),"该步骤不属于本阶段！");

        //试剂列表
        List<ExperimentStepReagentVo> stepItems=experimentStepReagentService.selectExperimentStepReagentVoList(experimentId,phase.getId(),step.getId());
        List<ExperimentStepReagentVo> stepKitReagents=stepItems.stream().filter(e -> ExperimentStepReagentTypeEnum.KIT.getValue().equals(e.getType())).collect(Collectors.toList());
        List<ExperimentStepReagentVo> stepReagents=stepItems.stream().filter(e -> ExperimentStepReagentTypeEnum.REAGENT.getValue().equals(e.getType())).collect(Collectors.toList());

        //kit
        List<Long> kitIds=stepKitReagents.stream().map(ExperimentStepReagentVo::getKitId).distinct().collect(Collectors.toList());
        List<Kit> kits=kitService.selectByIds(kitIds);
        List<FileManage> kitInstructions=fileManageService.selectList(OssFileEnum.KitInstructionFile,kitIds);

        List<ExperimentStepReagentVo> stepKits=new ArrayList<>();
        List<String> kitUuids=stepKitReagents.stream().map(ExperimentStepReagentVo::getUuid).distinct().collect(Collectors.toList());
        kitUuids.forEach(uuid -> {
            List<ExperimentStepReagentVo> oneKit=stepKitReagents.stream().filter(e -> e.getUuid().equals(uuid)).collect(Collectors.toList());
            if(oneKit.size()>0){
                ExperimentStepReagentVo reagent=oneKit.get(0);
                Kit kit=kits.stream().filter(k -> k.getId().equals(reagent.getKitId())).findFirst().orElse(null);
                List<FileManage> oneKitInstructions=kitInstructions.stream().filter(i -> i.getReferDataId().equals(kit.getId())).collect(Collectors.toList());
                if(kit!=null){
                    ExperimentStepReagentVo stepKitVo=new ExperimentStepReagentVo();
                    stepKitVo.setId(0L);
                    stepKitVo.setKitId(kit.getId());
                    stepKitVo.setFirstReagentTypeId(reagent.getFirstReagentTypeId());
                    stepKitVo.setType(ExperimentStepReagentTypeEnum.KIT.getValue());
                    stepKitVo.setClassify(kit.getClassify());
                    stepKitVo.setName(kit.getName());
                    stepKitVo.setAmount(reagent.getAmount());
                    stepKitVo.setUuid(uuid);
                    stepKitVo.setUnit(reagent.getUnit());
                    stepKitVo.setInstructions(oneKitInstructions);
                    stepKits.add(stepKitVo);
                }
            }
        });
        stepReagents.addAll(stepKits);

        //实验阶段数
        int phaseCount=experimentPhaseService.selectCount(experimentId);

        ExperimentStepDetailVo stepDetailVo=new ExperimentStepDetailVo();
        stepDetailVo.setExperimentId(experimentId);
        stepDetailVo.setExperimentName(experiment.getName());
        stepDetailVo.setExperimentDescription(experiment.getDescription());
        stepDetailVo.setPhaseId(phaseId);
        stepDetailVo.setPhaseSort(phase.getSort());
        stepDetailVo.setPhaseName(phase.getName());
        stepDetailVo.setPhaseDescription(phase.getDescription());
        stepDetailVo.setStepId(stepId);
        stepDetailVo.setStepSort(step.getSort());
        stepDetailVo.setStepContent(step.getContent());
        stepDetailVo.setStepState(step.getState());
        stepDetailVo.setSingle(phaseCount == 1);
        stepDetailVo.setReagentList(stepReagents);

        //tips
        ExperimentTipsVo tips=experimentLogic.getTips(stepId);
        stepDetailVo.setTipsNum(StringUtils.isEmpty(step.getTips())?tips.getTipsFileList().size():tips.getTipsFileList().size()+1);

        //reagent
        int rc=stepReagents.size();
        stepDetailVo.setReagentNum(rc);

        //plate
        List<PlateStepRelate> relates=plateStepRelateService.selectByExperimentIdAndPhaseIdAndGtStepSort(experimentId,phaseId,step.getSort());
        List<Long> plateIds=relates.stream().map(PlateStepRelate::getPlateId).collect(Collectors.toList());
        List<Plate> plateList=plateService.selectListByIds(plateIds);
        stepDetailVo.setPlateNum(plateList.size());

        //hasTroubleShooting
        List<Experiment> experiments = experimentService.getExperimentList(experiment.getTopicExperimentId(),null);
        List<Experiment> sortedExperiments=experiments.stream().sorted(Comparator.comparingLong(e -> e.getCreateTime().getTime())).collect(Collectors.toList());
        experiment=experiments.stream().filter(e -> e.getId().equals(experimentId)).findFirst().orElse(null);
        int thisIndex=sortedExperiments.indexOf(experiment);
        if(thisIndex>0){
            Experiment before = sortedExperiments.get(thisIndex -1);
            List<ExperimentTroubleShooting> troubleShootings=experimentTroubleShootingService.selectByExperimentId(before.getId());
            if(CollectionUtils.isEmpty(troubleShootings)){
                stepDetailVo.setHasTroubleShooting(false);
            }else {
                stepDetailVo.setHasTroubleShooting(true);
            }
        }else {
            stepDetailVo.setHasTroubleShooting(false);
        }

        return stepDetailVo;
    }

    /**
     * 实验步骤试剂可导入列表 TODO
     * @param experimentId
     * @param phaseId
     * @param stepId
     * @param labId
     * @return
     */
    public MethodStepReagentImportVo getNewestStepAndExperimentStepReagents(Long experimentId,Long phaseId,Long stepId,Long labId,Long userId,String userName) {

        //实验
        Experiment experiment=experimentService.selectById(experimentId);
        Assert.notNull(experiment,"实验不存在！");
        Assert.isTrue(experiment.getLabId().equals(labId),"实验不属于该实验室！");

        //阶段
        ExperimentPhase phase=experimentPhaseService.selectById(phaseId);
        Assert.notNull(phase,"实验阶段不存在！");
        Assert.isTrue(phase.getExperimentId().equals(experimentId),"该阶段不属于本实验！");

        //步骤
        ExperimentStep step=experimentStepService.selectById(stepId);
        Assert.notNull(step,"实验步骤不存在！");
        Assert.isTrue(step.getExperimentId().equals(experimentId),"该步骤不属于本实验！");
        Assert.isTrue(step.getExperimentPhaseId().equals(phaseId),"该步骤不属于本阶段！");

        //试剂列表
        List<ExperimentStepReagentVo> stepReagents=experimentStepReagentService.selectExperimentStepReagentVoList(experimentId,phase.getId(),step.getId());

        if(step.getMethodStepId() != null){
            //是从方法导入的
            MethodPhase methodPhase=methodPhaseService.selectById(phase.getMethodPhaseId());
            MethodStep methodStep=methodStepService.selectById(step.getMethodStepId());
            Method method=methodService.getById(methodStep.getMethodId());

            if(method.getRecommendMethodId() != null && CollectionUtils.isEmpty(stepReagents)){
                //是推荐方法 并且实验未关联过试剂
                Method srcMethod=methodService.getById(method.getRecommendMethodId());
                MethodPhase srcMethodPhase=methodPhaseService.selectById(methodPhase.getSourcePhaseId());
                MethodStep srcMethodStep=methodStepService.selectById(methodStep.getSourceStepId());

                //步骤未关联试剂,查找最新关联试剂同步
                List<Method> methodList=methodService.listByRecommendMethodId(method.getRecommendMethodId());
                Method last=methodList.stream().filter(methodE -> {
                    MethodPhase latestPhase=methodPhaseService.listByMethodId(methodE.getId(),BoolEnum.FALSE).stream().filter(e -> e.getSort().equals(phase.getSort())).findFirst().orElse(null);
                    Assert.notNull(latestPhase,"阶段不存在！");
                    MethodStep latestStep=methodStepService.listByMethodId(methodE.getId(),BoolEnum.FALSE).stream().filter(e -> e.getMethodPhaseId().equals(latestPhase.getId()) && e.getSort().equals(step.getSort())).findFirst().orElse(null);
                    Assert.notNull(latestStep,"步骤不存在！");

                    List<MethodRelateReagent> relateReagents=methodRelateReagentService.listByStepId(latestStep.getId());

                    //关联过试剂  从最新关联的方法中同步试剂到实验
                    String latestContent=latestStep.getContent().replaceAll("[#][$][{][<]([0-9a-zA-Z]{32})[>][}][$][#]","").trim();
                    String srcContent=srcMethodStep.getContent().replaceAll("[#][$][{][<]([0-9a-zA-Z]{32})[>][}][$][#]","").trim();

                    return !CollectionUtils.isEmpty(relateReagents) && srcContent.equals(latestContent);
                }).max(Comparator.comparing(Method::getUpdateTime)).orElse(null);

                if(last!=null){
                    MethodPhase latestPhase=methodPhaseService.listByMethodId(last.getId(),BoolEnum.FALSE).stream().filter(e -> e.getSort().equals(phase.getSort())).findFirst().orElse(null);
                    Assert.notNull(latestPhase,"阶段不存在！");
                    MethodStep latestStep=methodStepService.listByMethodId(last.getId(),BoolEnum.FALSE).stream().filter(e -> e.getMethodPhaseId().equals(latestPhase.getId()) && e.getSort().equals(step.getSort())).findFirst().orElse(null);
                    Assert.notNull(latestStep,"步骤不存在！");

                    List<MethodRelateReagentVo> relateReagents=methodRelateReagentService.selectVoList(latestStep.getId());

                    MethodStepReagentImportVo methodStepDetail=new MethodStepReagentImportVo();
                    BeanUtils.copyProperties(latestStep,methodStepDetail);
                    methodStepDetail.setReagentList(relateReagents);
                    methodStepDetail.setUserId(userId);
                    methodStepDetail.setUserName(userName);
                    return methodStepDetail;
                }
                return null;
            }
            return null;
        }
        return null;
    }

    /**
     * 实验步骤导入试剂同步 TODO
     * @param methodStepId
     * @param experimentId
     * @param experimentPhaseId
     * @param experimentStepId
     * @param labId
     */
    public void importMethodRelateReagentToExperimentStepReagents(Long methodStepId,Long experimentId,Long experimentPhaseId,Long experimentStepId,Long labId,Long labMemberId){
        //实验
        Experiment experiment=experimentService.selectById(experimentId);
        Assert.notNull(experiment,"实验不存在！");
        Assert.isTrue(experiment.getLabId().equals(labId),"实验不属于该实验室！");
        Assert.isTrue(experiment.getExecutorId().equals(labMemberId),"您不是该实验执行人！");

        //阶段
        ExperimentPhase phase=experimentPhaseService.selectById(experimentPhaseId);
        Assert.notNull(phase,"实验阶段不存在！");
        Assert.isTrue(phase.getExperimentId().equals(experimentId),"该阶段不属于本实验！");

        //步骤
        ExperimentStep step=experimentStepService.selectById(experimentStepId);
        Assert.notNull(step,"实验步骤不存在！");
        Assert.isTrue(step.getExperimentId().equals(experimentId),"该步骤不属于本实验！");
        Assert.isTrue(step.getExperimentPhaseId().equals(experimentPhaseId),"该步骤不属于本阶段！");

        if(step.getMethodStepId() != null){
            //实验的方法
            Method exMethod=methodService.getById(experiment.getMethodId());
            Assert.notNull(exMethod,"实验方法来源不存在！");
            MethodPhase exMethodPhase=methodPhaseService.selectById(phase.getMethodPhaseId());
            Assert.notNull(exMethodPhase,"实验步骤来源不存在！");
            MethodStep exMethodStep=methodStepService.selectById(step.getMethodStepId());

            //导入源方法
            MethodStep latestStep=methodStepService.selectById(methodStepId);
            Assert.notNull(latestStep,"步骤不存在！");
            MethodPhase latestPhase=methodPhaseService.selectById(latestStep.getMethodPhaseId());
            Assert.notNull(latestPhase,"阶段不存在！");
            Method method=methodService.getById(latestPhase.getMethodId());
            Assert.isTrue(method.getSourceMethodId().equals(exMethod.getSourceMethodId()),"非同源方法，无法同步！");

            List<MethodRelateReagent> relateReagents=methodRelateReagentService.listByStepId(latestStep.getId());
            List<MethodRelateTimer> relateTimers=methodRelateTimerService.listByStepId(latestStep.getId());
            if(!CollectionUtils.isEmpty(relateReagents)){
                //关联过试剂  从最新关联的方法中同步试剂到实验
                String latestContent=latestStep.getContent().replaceAll("[#][$][{][<]([0-9a-zA-Z]{32})[>][}][$][#]","").trim();
                String exContent=exMethodStep.getContent().replaceAll("[#][$][{][<]([0-9a-zA-Z]{32})[>][}][$][#]","").trim();

                step.setContent(latestContent);
                experimentStepService.update(step);

                List<Long> reagentIds=relateReagents.stream().map(MethodRelateReagent::getReagentId).distinct().collect(Collectors.toList());
                List<Reagent> reagents=reagentService.selectByReagentIds(reagentIds);
                List<Long> reagentTypeIds=reagents.stream().map(Reagent::getReagentTypeId).distinct().collect(Collectors.toList());
                Map<Long, Long> firstReagentTypeMap=reagentTypeService.selectFirstReagentTypeMap(reagentTypeIds);
                Map<Integer, String> unitMap=dictService.getUnitMap();
                List<ExperimentStepReagent> stepReagentsToInsert=relateReagents.stream().map(methodRelateReagent -> {
                    ExperimentStepReagent experimentStepReagent=new ExperimentStepReagent();
                    experimentStepReagent.setExperimentId(experimentId);
                    experimentStepReagent.setPhaseId(phase.getId());
                    experimentStepReagent.setStepId(step.getId());
                    experimentStepReagent.setUuid(methodRelateReagent.getUuid());
                    experimentStepReagent.setReagentId(methodRelateReagent.getReagentId());
                    experimentStepReagent.setName(methodRelateReagent.getReagentName());
                    reagents.stream().filter(e -> e.getId().equals(methodRelateReagent.getReagentId())).findFirst().ifPresent(reagent -> {
                        experimentStepReagent.setFirstReagentTypeId(firstReagentTypeMap.get(reagent.getReagentTypeId()));
                        experimentStepReagent.setClassify(reagent.getClassify());
                        experimentStepReagent.setAlias(reagent.getAlias());
                        experimentStepReagent.setUnit(unitMap.get(reagent.getUnit()));
                    });
                    return experimentStepReagent;
                }).collect(Collectors.toList());
                if(!CollectionUtils.isEmpty(stepReagentsToInsert)){
                    experimentStepReagentService.insertBatch(stepReagentsToInsert);
                }

                List<ExperimentStepTimer> stepTimersToInsert=relateTimers.stream().map(methodRelateTimer -> {
                    ExperimentStepTimer experimentStepTimer=new ExperimentStepTimer();
                    experimentStepTimer.setExperimentId(experimentId);
                    experimentStepTimer.setPhaseId(phase.getId());
                    experimentStepTimer.setStepId(step.getId());
                    experimentStepTimer.setTime(methodRelateTimer.getTime());
                    experimentStepTimer.setRemainTime(methodRelateTimer.getTime());
                    return experimentStepTimer;
                }).collect(Collectors.toList());
                if(!CollectionUtils.isEmpty(stepTimersToInsert)){
                    experimentStepTimerService.insertBatch(stepTimersToInsert);
                }

                if(exContent.equals(latestContent)){
                    //步骤内容未修改 同步到方法
                    exMethodStep.setContent(latestStep.getContent());
                    methodStepService.updateById(exMethodStep);

                    List<MethodRelateReagent> relateReagentsToInsert=relateReagents.stream().peek(e -> {
                        e.setId(null);
                        e.setMethodId(method.getId());
                        e.setPhaseId(exMethodPhase.getId());
                        e.setStepId(exMethodStep.getId());
                        e.setUpdateTime(null);
                        e.setCreateTime(null);
                    }).collect(Collectors.toList());
                    if(!CollectionUtils.isEmpty(relateReagentsToInsert)){
                        methodRelateReagentService.saveRelateReagentList(relateReagentsToInsert);
                    }

                    List<MethodRelateTimer> relateTimersToInsert=relateTimers.stream().peek(e -> {
                        e.setId(null);
                        e.setMethodId(method.getId());
                        e.setPhaseId(exMethodPhase.getId());
                        e.setStepId(exMethodStep.getId());
                        e.setUpdateTime(null);
                        e.setCreateTime(null);
                    }).collect(Collectors.toList());
                    if(!CollectionUtils.isEmpty(relateTimersToInsert)){
                        methodRelateTimerService.saveList(relateTimersToInsert);
                    }
                }
            }
        }
    }

    /**
     * 实验步骤 试剂/样品 别名修改
     * @param experimentId
     * @param phaseId
     * @param stepId
     * @param aliases
     * @param userInfoVo
     */
    public void aliasModify(Long experimentId,Long phaseId,Long stepId,List<Alias> aliases,UserInfoVo userInfoVo) {
        //校验
        experimentStepService.getExperimentStepAndAssertExist(experimentId,phaseId,stepId,userInfoVo.getLabId(),userInfoVo.getLabMemberId());

        List<Alias> billAlias=aliases.stream().filter(e -> e.getType().equals(ExperimentStepMaterialTypeEnum.EXPERIMENT_SAMPLE.getType())).collect(Collectors.toList());
        List<Alias> reagentAlias=aliases.stream().filter(e -> e.getType().equals(ExperimentStepMaterialTypeEnum.STEP_REAGENT.getType())).collect(Collectors.toList());

        //bill stepReagent
        List<Long> billIds=billAlias.stream().map(Alias::getStepReagentId).distinct().collect(Collectors.toList());
        List<Long> stepReagentIds=reagentAlias.stream().map(Alias::getStepReagentId).distinct().collect(Collectors.toList());
        List<ExperimentBill> bills=experimentBillService.selectList(billIds);
        List<ExperimentStepReagent> reagents=experimentStepReagentService.selectList(stepReagentIds);
        List<ExperimentBill> stepBills = experimentBillService.selectInStepReagentIds(stepReagentIds);
        bills.addAll(stepBills);

        //experimentProduce
        List<Long> produceIds=bills.stream().filter(e -> e.getSource().equals(ExperimentBillSourceEnum.EXPERIMENT_PRODUCT.getSource())).map(ExperimentBill::getSourceId).distinct().collect(Collectors.toList());
        List<ExperimentProduce> produces = experimentProduceService.selectList(produceIds);

        //reagent
        List<Long> reagentIdFrBil=bills.stream().map(ExperimentBill::getSourceId).collect(Collectors.toList());
        List<Long> reagentIdFrSr=reagents.stream().map(ExperimentStepReagent::getReagentId).collect(Collectors.toList());
        reagentIdFrBil.addAll(reagentIdFrSr);
        List<Long> allReagentIds=reagentIdFrBil.stream().distinct().collect(Collectors.toList());
        List<Reagent> reagentG=reagentService.selectByReagentIds(allReagentIds);

        List<Long> kitIds=reagentG.stream().map(Reagent::getKitId).distinct().collect(Collectors.toList());
        List<Kit> kits=kitService.selectByIds(kitIds);

        List<Reagent> updateRG = new ArrayList<>();
        List<Kit> updateKit = new ArrayList<>();
        List<ExperimentProduce> updateProduces = new ArrayList<>();

        //bill
        List<ExperimentBill> billUpdate = new ArrayList<>();
        if(!StringUtils.isEmpty(billAlias)){
            for (Alias alias : billAlias){
                ExperimentBill bill=bills.stream().filter(e -> e.getId().equals(alias.getStepReagentId())).findFirst().orElse(null);
                if(bill!=null){
                    bill.setAlias(alias.getAlias());
                    billUpdate.add(bill);

                    if(bill.getSource().equals(ExperimentBillSourceEnum.REAGENT.getSource())){
                        Reagent reagent=reagentG.stream().filter(e -> e.getId().equals(bill.getSourceId())).findFirst().orElse(null);
                        if(reagent!=null){
                            Kit kit=kits.stream().filter(e -> e.getId().equals(reagent.getKitId())).findFirst().orElse(null);
                            if(null != kit && kit.getKitType().equals(KitEnum.KitType.ONE.getValue())){
                                kit.setAlias(bill.getAlias());
                                updateKit.add(kit);
                                kits.remove(kit);
                            }
                            reagent.setAbbr(bill.getAlias());
                            updateRG.add(reagent);
                            reagentG.remove(reagent);
                        }
                    }else if(bill.getSource().equals(ExperimentBillSourceEnum.EXPERIMENT_PRODUCT.getSource())){
                        ExperimentProduce experimentProduce=produces.stream().filter(e -> e.getId().equals(bill.getSourceId())).findFirst().orElse(null);
                        if(experimentProduce!=null){
                            experimentProduce.setAlias(bill.getAlias());
                            updateProduces.add(experimentProduce);
                            produces.remove(experimentProduce);
                        }
                    }
                }
            }
        }

        //step 更新stepReagent stepBill
        List<ExperimentStepReagent> reagentUpdate = new ArrayList<>();
        if(!StringUtils.isEmpty(reagentAlias)){
            for (Alias alias : reagentAlias){
                ExperimentStepReagent stepReagent=reagents.stream().filter(e -> e.getId().equals(alias.getStepReagentId())).findFirst().orElse(null);
                if(stepReagent!=null){
                    stepReagent.setAlias(alias.getAlias());
                    reagentUpdate.add(stepReagent);
                    Reagent reagent=reagentG.stream().filter(e -> e.getId().equals(stepReagent.getReagentId())).findFirst().orElse(null);
                    if(reagent!=null){
                        Kit kit=kits.stream().filter(e -> e.getId().equals(reagent.getKitId())).findFirst().orElse(null);
                        if(null != kit && kit.getKitType().equals(KitEnum.KitType.ONE.getValue())){
                            kit.setAbbr(stepReagent.getAlias());
                            updateKit.add(kit);
                            kits.remove(kit);
                        }
                        reagent.setAbbr(stepReagent.getAlias());
                        updateRG.add(reagent);
                        reagentG.remove(reagent);
                    }
                }
            }
        }

        //执行更新
        if(reagentUpdate.size()>0){
            experimentStepReagentService.updateBatch(reagentUpdate);
        }

        if(billUpdate.size()>0){
            experimentBillService.updateBatch(billUpdate);
        }

        if(aliases.size()>0){
            plateGridReagentService.updateAliasBatch(aliases);
        }

        if(!CollectionUtils.isEmpty(updateRG)){
            reagentService.updateAliasBatch(updateRG);
        }

        if(!CollectionUtils.isEmpty(updateKit)){
            kitService.updateAliasBatch(updateKit);
        }

        if(!CollectionUtils.isEmpty(updateProduces)){
            experimentProduceService.updateAliasBatch(updateProduces);
        }
    }

    /**
     * 删除实验步骤中的试剂
     * @param experimentId
     * @param phaseId
     * @param stepId
     * @param uuid
     * @param userInfoVo
     */
    public void reagentDelete(Long experimentId,Long phaseId,Long stepId,Long id,String uuid,Integer type,UserInfoVo userInfoVo) {
        //校验
        ExperimentStep experimentStep=experimentStepService.getExperimentStepAndAssertExist(experimentId,phaseId,stepId,userInfoVo.getLabId(),userInfoVo.getLabMemberId());

        List<ExperimentBill> experimentBill;
        List<Long> ids;
        if(type!=null){
            Assert.isTrue(!StringUtils.isEmpty(uuid),"uuid is empty !");
            List<ExperimentStepReagent> stepReagents=experimentStepReagentService.selectByUuidAndStepId(uuid,stepId,type);
            ids=stepReagents.stream().map(ExperimentStepReagent::getId).distinct().collect(Collectors.toList());

            experimentBill=experimentBillService.selectByStepReagentIds(ids);


            if(stepReagents!=null && stepReagents.size()>0){
                //删除文本中的试剂
                String text="#${[reagent]<" + uuid + ">}$#";
                String content=experimentStep.getContent();
                content=content.replace(text,"");
                experimentStep.setContent(content);
                experimentStepService.update(experimentStep);

                //删除步骤试剂
                experimentStepReagentService.deleteByIds(ids);
            }
        }else {

            ExperimentStepReagent stepReagent=experimentStepReagentService.selectById(id);

            experimentBill=experimentBillService.selectByStepReagentId(id);

            ids = new ArrayList<>();
            ids.add(id);

            if(stepReagent!=null){
                //删除文本中的试剂
                uuid="#${[reagent]<" + stepReagent.getUuid() + ">}$#";
                String content=experimentStep.getContent();
                content=content.replace(uuid,"");
                experimentStep.setContent(content);
                experimentStepService.update(experimentStep);

                //删除步骤试剂
                experimentStepReagentService.deleteById(id);
            }

        }

        //gridReagent gridIds
        List<PlateGridReagent> plateGridReagents = plateGridReagentService.selectListBySourceIdAndType(ids,ExperimentStepMaterialTypeEnum.EXPERIMENT_SAMPLE.getType());
        List<Long> gridIds=plateGridReagents.stream().map(PlateGridReagent::getPlateGridId).distinct().collect(Collectors.toList());

        //删除stepBill
        if(experimentBill!=null){
            List<Long> billIds=experimentBill.stream().map(ExperimentBill::getId).distinct().collect(Collectors.toList());
            experimentBillService.deleteByIds(billIds);
            //删除gridReagent
            plateGridReagentService.deleteBySourceIdAndType(billIds,ExperimentStepMaterialTypeEnum.EXPERIMENT_SAMPLE.getType());
        }

        //isUsed
        experimentPlateLogic.setGridNotUseForReagentAndTime(gridIds);
    }

    public void getExperimentStepAndAssertExist(Long experimentId,Long phaseId,Long stepId,Long labId,Long labMemberId) {
        Experiment experiment=experimentService.selectById(experimentId);
        Assert.notNull(experiment,"实验不存在！");
        Assert.isTrue(experiment.getLabId().equals(labId),"实验不属于该实验室！");
        if(labMemberId!=null){
            Assert.isTrue(experiment.getExecutorId().equals(labMemberId),"您不是该实验的执行人，无法进行此操作！");
        }
        if(phaseId!=null && stepId!=null){
            ExperimentPhase phase=experimentPhaseService.selectById(phaseId);
            Assert.notNull(phase,"实验阶段不存在！");
            Assert.isTrue(phase.getExperimentId().equals(experimentId) ,"该阶段不属于本实验！");

            ExperimentStep step=experimentStepService.selectById(stepId);
            Assert.notNull(step,"实验步骤不存在！");
            Assert.isTrue(step.getExperimentId().equals(experimentId) ,"该步骤不属于本实验！");
            Assert.isTrue(step.getExperimentPhaseId().equals(phase.getId()) ,"该步骤不属于本阶段！");
        }

    }

    /**
     * 实验步骤中删除文本
     * @param experimentId
     * @param phaseId
     * @param stepId
     * @param textId
     * @param labId
     * @param labMemberId
     */
    public void textDelete(Long experimentId,Long phaseId,Long stepId,Long textId,Long labId,Long labMemberId) {

        //experiment校验
        experimentStepService.getExperimentStepAndAssertExist(experimentId,phaseId,stepId,labId,labMemberId);

        //stepText校验
        ExperimentStepText stepText=experimentStepTextService.selectById(textId);
        Assert.notNull(stepText,"实验步骤文本不存在！");

        //删除stepText
        experimentStepTextService.deleteById(textId);

        //plateGridTexts gridIds
        List<PlateGridText> plateGridTexts = plateGridTextService.selectListByTextId(textId);
        List<Long> gridIds=plateGridTexts.stream().map(PlateGridText::getPlateGridId).distinct().collect(Collectors.toList());

        //删除gridText
        plateGridTextService.deleteByStepTextId(textId);

        //isUsed
        experimentPlateLogic.setGridNotUseForText(gridIds);
    }

    /**
     * 删除实验相关的所有内容bill reagent timer text plateReagent plateTimer plateText
     * @param experimentId
     */
    public void deleteAllContents(Long experimentId) {
        experimentBillService.delete(experimentId);
        experimentStepReagentService.deleteByExperimentId(experimentId);
        experimentStepTimerService.deleteByExperimentId(experimentId);
        experimentStepTextService.deleteByExperimentId(experimentId);
        plateGridReagentService.deleteByExperimentId(experimentId);
        plateGridTextService.deleteByExperimentId(experimentId);
        plateGridTimerService.deleteByExperimentId(experimentId);
    }

}
